// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == 'object' && typeof module == 'object')
    // CommonJS
    mod(require('../../lib/codemirror'));
  else if (typeof define == 'function' && define.amd)
    // AMD
    define(['../../lib/codemirror'], mod);
  // Plain browser env
  else mod(CodeMirror);
})(function(CodeMirror) {
  'use strict';

  CodeMirror.defineMode('solr', function() {
    'use strict';

    var isStringChar = /[^\s\|\!\+\-\*\?\~\^\&\:\(\)\[\]\{\}\"\\]/;
    var isOperatorChar = /[\|\!\+\-\*\?\~\^\&]/;
    var isOperatorString = /^(OR|AND|NOT|TO)$/i;

    function isNumber(word) {
      return parseFloat(word).toString() === word;
    }

    function tokenString(quote) {
      return function(stream, state) {
        var escaped = false,
          next;
        while ((next = stream.next()) != null) {
          if (next == quote && !escaped) break;
          escaped = !escaped && next == '\\';
        }

        if (!escaped) state.tokenize = tokenBase;
        return 'string';
      };
    }

    function tokenOperator(operator) {
      return function(stream, state) {
        var style = 'operator';
        if (operator == '+') style += ' positive';
        else if (operator == '-') style += ' negative';
        else if (operator == '|') stream.eat(/\|/);
        else if (operator == '&') stream.eat(/\&/);
        else if (operator == '^') style += ' boost';

        state.tokenize = tokenBase;
        return style;
      };
    }

    function tokenWord(ch) {
      return function(stream, state) {
        var word = ch;
        while ((ch = stream.peek()) && ch.match(isStringChar) != null) {
          word += stream.next();
        }

        state.tokenize = tokenBase;
        if (isOperatorString.test(word)) return 'operator';
        else if (isNumber(word)) return 'number';
        else if (stream.peek() == ':') return 'field';
        else return 'string';
      };
    }

    function tokenBase(stream, state) {
      var ch = stream.next();
      if (ch == '"') state.tokenize = tokenString(ch);
      else if (isOperatorChar.test(ch)) state.tokenize = tokenOperator(ch);
      else if (isStringChar.test(ch)) state.tokenize = tokenWord(ch);

      return state.tokenize != tokenBase ? state.tokenize(stream, state) : null;
    }

    return {
      startState: function() {
        return {
          tokenize: tokenBase,
        };
      },

      token: function(stream, state) {
        if (stream.eatSpace()) return null;
        return state.tokenize(stream, state);
      },
    };
  });

  CodeMirror.defineMIME('text/x-solr', 'solr');
});
